package com.my.ph.media.api;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.collection.ListUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.http.Header;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.my.ph.enums.MediaTypeEnum;
import com.my.ph.entity.media.TVMovie;
import com.my.ph.entity.media.TVMovieDetail;
import com.my.ph.util.HttpClientUtil;
import com.my.ph.util.UserJsonConfigUtil;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Component;

import java.net.http.HttpResponse;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

@Component
@RequiredArgsConstructor
public class TMDBApi {

    private Map<String, String> getHeader() {
        String tmdbAuthorization = UserJsonConfigUtil.getInstance().getTmdbAPIKey();
        if (StrUtil.isBlank(tmdbAuthorization)) throw new RuntimeException("请先配置tmdb接口API key");
        return Map.of("accept", "application/json", Header.AUTHORIZATION.toString(), "Bearer " + tmdbAuthorization);
    }

    private String getUrl(String url) {
        String tmdbBaseUrl = UserJsonConfigUtil.getInstance().getTmdbBaseUrl();
        if (StrUtil.isBlank(tmdbBaseUrl)) throw new RuntimeException("请先配置tmdb接口地址");
        return tmdbBaseUrl + url;
    }

    private HttpResponse<String> getResponse(String url) {
        HttpResponse<String> response = HttpClientUtil.get(url, getHeader());
        if (response.statusCode() == 401) throw new RuntimeException("请检擦API key配置是否正确");
        if (response.statusCode() != 200) throw new RuntimeException("请求发生异常");
        return response;
    }

    private HttpResponse<String> getTvMovieSearchResponse(String query, MediaTypeEnum mediaType, int page) {
        return getResponse(getUrl(StrUtil.format("/3/search/{}?query={}&include_adult={}&language={}&page={}", mediaType.getValue(), query, UserJsonConfigUtil.getInstance().isTmdbAdult(), "zh-CN", page)));
    }

    private HttpResponse<String> getTvMovieAlternativeTitles(long id, MediaTypeEnum mediaType) {
        return getResponse(getUrl(StrUtil.format("/3/{}/{}/alternative_titles?language={}", mediaType.getValue(), id, "zh-CN")));
    }

    private HttpResponse<String> getTvMovieCredits(long id, MediaTypeEnum mediaType) {
        return getResponse(getUrl(StrUtil.format("/3/{}/{}/credits?language={}", mediaType.getValue(), id, "zh-CN")));
    }

    private List<TVMovie> search(String query, MediaTypeEnum mediaType) {
        HttpResponse<String> response = getTvMovieSearchResponse(query, mediaType, 1);
        JSONObject bodyObj = JSONUtil.parseObj(response.body());
        Integer totalPages = bodyObj.getInt("total_pages");
        List<TVMovie> list = JSONUtil.toList(JSONUtil.parseObj(response.body()).getStr("results"), TVMovie.class);
        for (int i = 2; i <= totalPages && i <= 3; i++)
            list.addAll(JSONUtil.toList(JSONUtil.parseObj(getTvMovieSearchResponse(query, mediaType, i).body()).getStr("results"), TVMovie.class));
        if (CollectionUtil.isNotEmpty(list)) list.forEach(item -> item.setMediaType(mediaType.getValue()));
        return list;
    }

    public List<TVMovie> searchMovie(String query) {
        return search(query, MediaTypeEnum.MOVIE);
    }

    public List<TVMovie> searchTV(String query) {
        return search(query, MediaTypeEnum.TV);
    }

    public List<TVMovie> searchMoveTv(String query) {
        List<TVMovie> movies = searchMovie(query);
        List<TVMovie> tvs = searchTV(query);
        return ListUtil.sort(new ArrayList<>(){{
            if (CollectionUtil.isNotEmpty(movies)) addAll(movies);
            if (CollectionUtil.isNotEmpty(tvs)) addAll(tvs);
        }}, (o1, o2) -> (int) ((o2.getPopularity() - o1.getPopularity()) * 100));
    }

    private List<TVMovieDetail.AlternativeTitles> getAlternativeTitles(long id, MediaTypeEnum mediaType) {
        HttpResponse<String> response = getTvMovieAlternativeTitles(id, mediaType);
        JSONObject obj = JSONUtil.parseObj(response.body());
        List<TVMovieDetail.AlternativeTitles> titles = JSONUtil.toList(MediaTypeEnum.MOVIE.is(mediaType.getValue()) ? obj.getStr("titles") : obj.getStr("results"), TVMovieDetail.AlternativeTitles.class);
        List<TVMovieDetail.AlternativeTitles> result = new ArrayList<>();
        if (CollectionUtil.isNotEmpty(titles)) {
            List<TVMovieDetail.AlternativeTitles> tempList = titles.stream().filter(item -> (StrUtil.equals(item.getIso_3166_1(), "CN") && StrUtil.equals(item.getType(), ""))).toList();
            if (CollectionUtil.isNotEmpty(tempList)) result.add(tempList.get(0));
            tempList = titles.stream().filter(item -> (StrUtil.equals(item.getIso_3166_1(), "CN") && StrUtil.equals(item.getType(), "short title"))).toList();
            if (CollectionUtil.isNotEmpty(tempList)) result.add(tempList.get(0));
            tempList = titles.stream().filter(item -> (StrUtil.equals(item.getIso_3166_1(), "US") && StrUtil.equalsAny(item.getType(), "", "Alias"))).toList();
            if (CollectionUtil.isNotEmpty(tempList)) result.add(tempList.get(0));
            else titles.stream().filter(item -> (StrUtil.equals(item.getIso_3166_1(), "US"))).findFirst().ifPresent(result::add);
        }
        return CollectionUtil.isNotEmpty(result) ? CollectionUtil.reverse(result) : titles;
    }

    public JSONObject getCredits(long id, MediaTypeEnum mediaType) {
        HttpResponse<String> response = getTvMovieCredits(id, mediaType);
        return JSONUtil.parseObj(response.body());
    }

    public TVMovieDetail getDetail(long id, MediaTypeEnum mediaType) {
        HttpResponse<String> response = getResponse(getUrl(StrUtil.format("/3/{}/{}?language={}", mediaType.getValue(), id, "zh-CN")));
        TVMovieDetail bean = JSONUtil.toBean(response.body(), TVMovieDetail.class);
        bean.setTitles(getAlternativeTitles(id, mediaType));
        bean.setMediaType(mediaType.getValue());
        return bean;
    }

}
